home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2.0 - Programmer's Utilities Power Pack / Delphi 2.0 Programmer's Utilities Power Pack.iso / s_to_z / tpack / bitbox.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-09-15  |  14.5 KB  |  530 lines

  1. {------------------------------------------------------------------------------}
  2. {                                                                              }
  3. {------------------------------------------------------------------------------}
  4.  
  5. unit Bitbox;
  6.  
  7. {The SECOND implementation
  8. does multiple columns and rows smartly.
  9. understands text better.
  10. resizes imperfectly still}
  11.  
  12. {BitBox like Toolbars anyone? just kidding}
  13.  
  14. {THE POINT:  To create checkbox group components that will take a byte or word
  15. and provide dynamically sized boxes containing selected items from a universe
  16. of 8 or 16 choices. Allowing the user to check/set bits via a form.}
  17.  
  18. {this unit takes advantage of delphi's small set implementation, which works
  19. in bytes and words for sets with less than 9/17 members respectively.}
  20.  
  21. interface
  22.  
  23. uses
  24.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  25.   Forms, Dialogs, DB, DBTables, StdCtrls;
  26.  
  27. type
  28.   {define the word compatible set}
  29.   T16Bits = (Bit0,Bit1,Bit2,Bit3,Bit4,Bit5,Bit6,Bit7
  30.             ,Bit8,Bit9,BitA,BitB,BitC,BitD,BitE,BitF);
  31.   TWordSet = Set of T16Bits;
  32.   TWord = Record
  33.     x:Word;
  34.     end;
  35.  
  36.   TBoxOrientation = (boxVertical,boxHorizontal);
  37.  
  38.   {define a common groupbox for byte and word use}
  39.   TBitBox = class(TGroupBox)
  40.   private
  41.     fMembers: TWordSet;
  42.     fMask: TWordSet;
  43.     fCaptions: TStringList;
  44.     fHints: TStringList;
  45.     fOnChange: TNotifyEvent;
  46.     fReadOnly: Boolean;
  47.  
  48.     fBoxOrientation: TBoxOrientation;
  49.     fFromLeft: Byte;
  50.     fFromRight: Byte;
  51.     fColumns: Byte;
  52.     fMinTextWidth:Byte;
  53.     fMaxTextWidth:Integer;
  54.     fFromTop:Byte;
  55.     fRowHeight:Byte;
  56.     fColumnSpacing:Byte;
  57.  
  58.     procedure ChangeSelected(Sender:TObject); virtual;
  59.   protected
  60.     function GetMember:Word;
  61.     procedure SetMember(Value:Word);
  62.     procedure SetMembers(Value:TWordSet);
  63.     procedure SetMask(Value:TWordSet);
  64.     procedure SetCaptions(Value:TStringList);
  65.     procedure SetHints(Value:TStringList);
  66.     function GetMaxTextWidth:Integer;
  67.     procedure SetColumns(Value:Byte);
  68.     procedure SetFromTop(Value:Byte);
  69.     procedure SetRowHeight(Value:Byte);
  70.     procedure SetMinTextWidth(Value:Byte);
  71.     procedure SetMaxTextWidth(Value:Integer);
  72.     procedure SetColumnSpacing(Value:Byte);
  73.     procedure SetBoxOrientation(Value:TBoxOrientation);
  74.     procedure InitBox;
  75.   public
  76.     constructor Create(aOwner:TComponent); Override;
  77.     destructor Destroy; Override;
  78.     procedure Loaded; Override;
  79.     procedure Init; {[re]creates checkboxes from fUniverse/fMembers}
  80.     procedure UpdateAll;
  81.     procedure Update(Bit:T16Bits;aChecked:Boolean;aCaption:String); {updates chekbox}
  82.   published
  83.     property Numeric:  Word read GetMember write SetMember;
  84.     property Possible: TWordSet read fMask write SetMask;
  85.     property Selected: TWordSet read fMembers write SetMembers;
  86.     property ReadOnly: Boolean read fReadOnly write fReadOnly default False;
  87.     property Captions: TStringList read fCaptions write SetCaptions;
  88.     property Hints:    TStringList read fHints write SetHints;
  89.     property OnChange: TNotifyEvent read fOnChange write fOnChange;
  90.  
  91.     property BoxOrientation: TBoxOrientation read fBoxOrientation write SetBoxOrientation
  92.     {$IFDEF START_HORIZONTALLY}
  93.       default boxHorizontal;
  94.     {$ELSE}
  95.       default boxVertical;
  96.     {$ENDIF}
  97.     property Columns: Byte read fColumns write SetColumns
  98.     {$IFDEF START_HORIZONTALLY}
  99.       default 0;
  100.     {$ELSE}
  101.       default 2;
  102.     {$ENDIF}
  103.     property FromTop: Byte read fFromTop write fFromTop default 20;
  104.     property FromLeft: Byte read fFromLeft write fFromLeft default 10;
  105.     property FromRight: Byte read fFromRight write fFromRight default 5;
  106.     property RowHeight: Byte read fRowHeight write SetRowHeight default 20;
  107.     property ColumnSpacing:Byte read fColumnSpacing write SetColumnSpacing default 10;
  108.     property MinTextWidth:Byte read fMinTextWidth write SetMinTextWidth default 16;
  109.     property MaxTextWidth:Integer read GetMaxTextWidth write SetMaxTextWidth;
  110.     end;
  111.  
  112.   TdbBitBox = class(TBitBox)
  113.   private
  114.     FDataLink: TFieldDataLink;
  115.     procedure DataChange(Sender: TObject);
  116.     function GetDataField: string;
  117.     function GetDataSource: TDataSource;
  118.     function GetField: TField;
  119.     procedure SetDataField(const Value: string);
  120.     procedure SetDataSource(Value: TDataSource);
  121.     procedure ChangeSelected(Sender:TObject); override;
  122.     procedure UpdateData(Sender: TObject);
  123.     procedure EditingChange(Sender: TObject);
  124.   protected
  125.     function GetReadOnly: Boolean;
  126.     procedure SetReadOnly(Value: Boolean);
  127.     procedure Notification(AComponent: TComponent;
  128.       Operation: TOperation); override;
  129.   public
  130.     constructor Create(aOwner:TComponent); Override;
  131.     destructor Destroy; Override;
  132.     property Field: TField read GetField;
  133.   published
  134.     property DataField: string read GetDataField write SetDataField;
  135.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  136.     end;
  137.  
  138.  
  139. implementation
  140.  
  141. {------------------------------------------------------------------------------}
  142. { CREATE, PREPARE AND DISPOSE OF THE COMPONENT                                 }
  143. {------------------------------------------------------------------------------}
  144.  
  145. constructor TBitBox.Create(aOwner:TComponent);
  146. var
  147.   Bit: T16Bits;
  148. begin
  149.   inherited Create(aOwner);
  150.   fColumnSpacing:=10;
  151.   fFromTop:=20;
  152.   fFromLeft:=10;
  153.   fFromRight:=5;
  154.   fRowHeight:=20;
  155.   fMinTextWidth:=13;
  156.   {$IFDEF START_HORIZONTALLY}
  157.     fBoxOrientation:=boxHorizontal;
  158.     fColumns:=0;
  159.   {$ELSE}
  160.     fBoxOrientation:=boxVertical;
  161.     fMaxTextWidth:=100;
  162.     fColumns:=2;
  163.   {$ENDIF}
  164.   fCaptions:=TStringList.Create;
  165.   fHints:=TStringList.Create;
  166.   for Bit:= Bit0 to BitF do begin
  167.     Include(fMask,Bit);
  168.     fCaptions.Add('(Bit'+inttoStr(ord(bit))+')');
  169.     fHints.Add('(Bit'+inttoStr(ord(bit))+')');
  170.     end;
  171. end;
  172.  
  173. procedure TBitBox.Loaded;
  174. begin
  175.   inherited Loaded;
  176.   InitBox;
  177. end;
  178.  
  179. destructor TBitBox.Destroy;
  180. begin
  181.   fCaptions.Free;
  182.   fCaptions:=nil;
  183.   fHints.Free;
  184.   fHints:=nil;
  185.   inherited Destroy;
  186. end;
  187.  
  188. {------------------------------------------------------------------------------}
  189. { GET AND SET THE COMPONENT SPECIFIC PROPERTIES                                }
  190. {------------------------------------------------------------------------------}
  191.  
  192. function TBitBox.GetMember:Word;
  193. var
  194.   s:TWordSet;
  195. begin
  196.   s:=fMembers;
  197.   result:=tWord(s).x;
  198. end;
  199.  
  200. procedure TBitBox.SetMember(Value:Word);
  201. var
  202.   s:TWordSet;
  203. begin
  204.   s:=TWordSet(Value);
  205.   SetMembers(s);
  206. end;
  207.  
  208. procedure TBitBox.SetMembers(Value:TWordSet);
  209. begin
  210.   if fMembers<>Value then begin
  211.     fMembers:=Value;
  212.     UpdateAll;
  213.     end;
  214. end;
  215.  
  216. procedure TBitBox.SetMask(Value:TWordSet);
  217. begin
  218.   if fMask<>Value then begin
  219.     fMask:=Value;
  220.     init;
  221.     end;
  222. end;
  223.  
  224. procedure TBitBox.SetCaptions(Value:TStringList);
  225. begin
  226.   if fCaptions<>Value then begin {wow}
  227.     fCaptions.Assign(Value);
  228.     UpdateAll;
  229.     end;
  230. end;
  231.  
  232. procedure TBitBox.SetHints(Value:TStringList);
  233. begin
  234.   if fHints<>Value then begin
  235.     fHints.Assign(Value);
  236.     UpdateAll;
  237.     end;
  238. end;
  239.  
  240. procedure TBitBox.SetColumns(Value:Byte);
  241. begin
  242.   if fColumns<>Value then begin
  243.     fColumns:=Value;
  244.     Init;
  245.     end;
  246. end;
  247.  
  248. procedure TBitBox.SetRowHeight(Value:Byte);
  249. begin
  250.   if fRowHeight<>Value then begin
  251.     fRowHeight:=Value;
  252.     Init;
  253.     end;
  254. end;
  255.  
  256. procedure TBitBox.SetBoxOrientation(Value:TBoxOrientation);
  257. begin
  258.   if fBoxOrientation<>Value then begin
  259.     fBoxOrientation:=Value;
  260.     Init;
  261.     end;
  262. end;
  263.  
  264. procedure TBitBox.SetMinTextWidth(Value:Byte);
  265. begin
  266.   if fMinTextWidth<>Value then begin
  267.     fMinTextWidth:=Value;
  268.     Init;
  269.     end;
  270. end;
  271.  
  272. function TBitBox.GetMaxTextWidth:Integer;
  273. begin
  274.   if fMaxTextWidth<fMinTextWidth then
  275.     fMaxTextWidth:=fMinTextWidth;
  276.   Result:= fMaxTextWidth;
  277. end;
  278.  
  279. procedure TBitBox.SetMaxTextWidth(Value:Integer);
  280. begin
  281.   if fMaxTextWidth<>Value then begin
  282.     fMaxTextWidth:=Value;
  283.     Init;
  284.     end;
  285. end;
  286.  
  287. procedure TBitBox.SetColumnSpacing(Value:Byte);
  288. begin
  289.   if fColumnSpacing<>Value then begin
  290.     fColumnSpacing:=Value;
  291.     Init;
  292.     end;
  293. end;
  294.  
  295. procedure TBitBox.SetFromTop(Value:Byte);
  296. begin
  297.   if fFromTop<>Value then begin
  298.     fFromTop:=Value;
  299.     Init;
  300.     end;
  301. end;
  302.  
  303. {------------------------------------------------------------------------------}
  304. { INITIALIZE AND UPDATE ALL OR ONE CHECKBOX IN THE GROUP                       }
  305. {------------------------------------------------------------------------------}
  306.  
  307. procedure TBitBox.Init;
  308. begin
  309.   if not (csLoading in ComponentState) then
  310.     InitBox;
  311. end;
  312.  
  313. procedure TBitBox.InitBox;
  314. var
  315.   Cols,i,n:integer;
  316.   Bit:T16Bits;
  317.   c:TCheckBox;
  318.   col,row,percol:byte;
  319. begin
  320.   n:=ControlCount-1;
  321.   if n>-1 then
  322.     for i:=0 to n do
  323.       Controls[0].Free;     {free all owned controls. really.}
  324.   n:=0;
  325.   for bit:= Bit0 to BitF do {step and count how many we'll be making}
  326.     if bit in fMask then
  327.       n:=n+1;
  328.   if n=0 then {nothing to do} {shrink?}
  329.     exit;
  330.   Cols:=fColumns;
  331.   if Cols<=0 then
  332.     Cols:=1;
  333.   if (fBoxOrientation=boxHorizontal) and (fColumns<2) then
  334.     Cols:=n;  {adjust to all accross.}
  335.   percol:=n div Cols;          {figure out how many rows that'll be}
  336.   if (n mod Cols) >0 then  {adjust to get 2 rows for 3 items in 2 columns}
  337.     percol:=percol+1;
  338.   i:=FromLeft+FromRight+Cols*(fColumnSpacing+MaxTextWidth);
  339.   if Width<i then
  340.     Width:=i;
  341.   row:=0;
  342.   col:=0;
  343.   for bit:= Bit0 to BitF do
  344.     if bit in fMask then begin  {make new child controls}
  345.       c:=TCheckBox.Create(self);
  346.       with c do begin
  347.         Checked:= bit in fMembers;
  348.         end;
  349.       with c do begin
  350.         Tag:=ord(bit);
  351.         Caption:= fCaptions.Strings[Tag];
  352.         Hint:= fHints.Strings[Tag];
  353.         Parent:=Self;
  354.         OnClick:=ChangeSelected;
  355.         Left:=FromLeft+Col*(fColumnSpacing+fMaxTextWidth);
  356.         Width:=MaxTextWidth;
  357.         Top:=fFromTop+(Row*fRowHeight);
  358.         if fBoxOrientation=boxVertical then begin
  359.           Row:=row+1;
  360.           if Row=PerCol then begin
  361.             Row:=0;
  362.             Col:=Col+1;
  363.             end;
  364.           end
  365.         else begin
  366.           Col:=Col+1;
  367.           if Cols=Cols then begin
  368.             Col:=0;
  369.             Row:=Row+1;
  370.             end;
  371.           end;
  372.         end;
  373.       end;
  374.   if Height<(fRowHeight*(PerCol+1)) then;
  375.     Height:=(fRowHeight*(PerCol+1));
  376. end;
  377.  
  378. procedure TBitBox.UpdateAll;
  379. var
  380.   Bit:T16Bits;
  381. begin
  382.   for Bit:= Bit0 to BitF do
  383.     if Bit in fMask then
  384.       Update(Bit,Bit in fMembers,fCaptions.Strings[ord(Bit)])
  385. end;
  386.  
  387. procedure TBitBox.Update(Bit:T16Bits;aChecked:Boolean;aCaption:String);
  388. var
  389.   i,n:integer;
  390. begin
  391.   n:=ControlCount-1;
  392.   if n>-1 then
  393.     for i:=0 to n do
  394.       if Controls[i].Tag=ord(Bit) then
  395.         with TCheckBox(Controls[i]) do begin
  396.           Caption:=aCaption;
  397.           Checked:=aChecked;
  398.           break;
  399.           end;
  400. end;
  401.  
  402. {------------------------------------------------------------------------------}
  403. { PROCS FOR CUSTOM EVENTS                                                      }
  404. {------------------------------------------------------------------------------}
  405.  
  406. procedure TBitBox.ChangeSelected(Sender:TObject);
  407. var
  408.   c:TCheckBox;
  409.   b:T16Bits;
  410. begin
  411.   c:=TCheckBox(Sender);
  412.   b:=T16Bits(c.Tag); {remember, we're using the tag to hold the bit value of the checkbox}
  413.   if c.Checked then
  414.     fMembers:=fMembers+[b]
  415.   else
  416.     fMembers:=fMembers-[b];
  417.   if assigned(fOnChange) then
  418.     fOnchange(Sender);
  419. end;
  420.  
  421. {------------------------------------------------------------------------------}
  422. { PROCS TO ERECT THE DATASOURCE CONNECTED COMPONENT                            }
  423. {------------------------------------------------------------------------------}
  424.  
  425. constructor TdbBitBox.Create(aOwner:TComponent);
  426. begin
  427.   inherited Create(aOwner);
  428.   inherited ReadOnly := True;
  429.   FDataLink:= TFieldDataLink.Create;
  430.   FDataLink.OnDataChange:= DataChange;
  431.   FDataLink.Control := Self;
  432.   FDataLink.OnEditingChange := EditingChange;
  433.   FDataLink.OnUpdateData := UpdateData;
  434. end;
  435.  
  436. destructor TdbBitBox.Destroy;
  437. begin
  438.   FDataLink.Free;
  439.   FDataLink := nil;
  440.   fCaptions.Free;
  441.   fCaptions:=nil;
  442.   inherited Destroy;
  443. end;
  444.  
  445. procedure TdbBitBox.Notification(AComponent: TComponent;
  446.   Operation: TOperation);
  447. begin
  448.   inherited Notification(AComponent, Operation);
  449.   if (Operation = opRemove) and (FDataLink <> nil) and
  450.     (AComponent = DataSource) then DataSource := nil;
  451. end;
  452.  
  453. {------------------------------------------------------------------------------}
  454. { PLUMBING AND READ-ONLY                                                       }
  455. {------------------------------------------------------------------------------}
  456.  
  457. function TdbBitBox.GetDataSource: TDataSource;
  458. begin
  459.   Result := FDataLink.DataSource;
  460. end;
  461.  
  462. procedure TdbBitBox.SetDataSource(Value: TDataSource);
  463. begin
  464.   FDataLink.DataSource := Value;
  465. end;
  466.  
  467. function TdbBitBox.GetDataField: string;
  468. begin
  469.   Result := FDataLink.FieldName;
  470. end;
  471.  
  472. procedure TdbBitBox.SetDataField(const Value: string);
  473. begin
  474.   FDataLink.FieldName := Value;
  475. end;
  476.  
  477. function TdbBitBox.GetField: TField;
  478. begin
  479.   Result := FDataLink.Field;
  480. end;
  481.  
  482. function TdbBitBox.GetReadOnly: Boolean;
  483. begin
  484.   Result := FDataLink.ReadOnly;
  485. end;
  486.  
  487. procedure TdbBitBox.SetReadOnly(Value: Boolean);
  488. begin
  489.   FDataLink.ReadOnly := Value;
  490. end;
  491.  
  492. {------------------------------------------------------------------------------}
  493. {                                                                              }
  494. {------------------------------------------------------------------------------}
  495.  
  496. procedure TdbBitBox.DataChange(Sender: TObject);
  497. begin
  498.   if FDataLink.Field <> nil then
  499.     Numeric := FDataLink.Field.AsInteger
  500.   else
  501.     if csDesigning in ComponentState then Numeric := 0;
  502. end;
  503.  
  504. procedure TdbBitBox.ChangeSelected(Sender:TObject);
  505. begin
  506.   inherited ChangeSelected(Sender);
  507.   if FDataLink.Field <> nil then
  508.     if not (csDesigning in ComponentState) then
  509.       UpdateData(Sender);
  510. end;
  511.  
  512. procedure TdbBitBox.EditingChange(Sender: TObject);
  513. begin
  514.   inherited ReadOnly := not FDataLink.Editing;
  515. end;
  516.  
  517. procedure TdbBitBox.UpdateData(Sender: TObject);
  518. begin
  519.   if Numeric<>FDataLink.Field.AsInteger then
  520.     if FDataLink.Edit then
  521.       FDataLink.Field.AsInteger:= Numeric;
  522. end;
  523.  
  524.  
  525. {------------------------------------------------------------------------------}
  526. {                                                                              }
  527. {------------------------------------------------------------------------------}
  528.  
  529. end.
  530.